home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-07-31 | 15.0 KB | 544 lines | [TEXT/MMCC] |
- /**************************************************************************
- LGBRadio
-
- Public domain, by Zig Zichterman.
-
- This class implements 3D radio buttons according to the guidelines
- suggested in _develop_ 15. Some of the drawing code is taken from
- the public domain source accompanying _develop_ 15.
-
- 07/31/94 zz Draw 3D if 4-bit grey, BW if 4-bit color
- 07/31/94 zz save/restore pen colors
- 1.0b3
- 07/28/94 zz add offscreen drawing for less flashy TextBox()
- 1.0b2 (never released)
- 07/20/94 zz call PenNormal() before drawing anything!
- 1.01b1
- **************************************************************************/
- #include "LGBRadio.h"
-
- #include <GestaltEqu.h>
-
- #include "LGBControl.h"
- #include "LGBDeviceIterator.h"
- #include "UGBDraw.h"
-
- /**************************************************************************
- Main() [static]
-
- Main entry point for all radio button calls. Dispatch according to
- message.
- **************************************************************************/
- long
- LGBRadio::Main(short inVariation, ControlHandle ioControl,
- short inMsg, long ioParam)
- {
- long returnMe = 0;
-
- // lock the control handle for the duration of this call
- char state = ::HGetState((Handle) ioControl);
- ::HLock((Handle) ioControl);
-
- LGBRadio radio(*ioControl,(inVariation & useWFont)?true:false);
-
- switch (inMsg) {
- case drawCntl :
- radio.Draw(ioParam);
- break;
-
- case testCntl :
- {
- Point hitPt;
- hitPt.h = LoWord(ioParam);
- hitPt.v = HiWord(ioParam);
- if (radio.Test(hitPt)) {
- returnMe = inButton;
- }
- }
- break;
-
- case calcCRgns : // only called in 24-bit mode
- { // is 32-bit addressing off?
- long result = 0;
- OSErr err = ::Gestalt(gestaltAddressingModeAttr,&result);
- if (!err && ((result &
- (1L << gestalt32BitAddressing)) == 0)) {
- RgnHandle rgn = (RgnHandle)
- ::StripAddress((Ptr) ioParam);
- radio.CalcCRgn(rgn);
- }
- }
- break;
-
- case calcCntlRgn : // only called in 32-bit mode
- radio.CalcCRgn((RgnHandle) ioParam);
- break;
- }
-
- // unlock handle
- ::HSetState((Handle) ioControl,state);
- return returnMe;
- }
-
- //—————————————————————————————————————————————————————————————————————————
- // Constructor
- //—————————————————————————————————————————————————————————————————————————
-
- /**************************************************************************
- LGBRadio(ControlHandle,Boolean)
-
- construct/initialize a control object. Just stores the control handle
- and the "should I use the window font?" flag in data members.
- **************************************************************************/
- LGBRadio::LGBRadio(ControlRecord *inControl, Boolean inUseWFont)
- : mControl(inControl), mUseWFont(inUseWFont)
- {
-
- }
-
- //—————————————————————————————————————————————————————————————————————————
- // Dispatch entry points
- //—————————————————————————————————————————————————————————————————————————
-
- /**************************************************************************
- Draw()
-
- Draw the control. inPartCode is a part code specifying which part of
- the control to draw, or 0 for the entire control.
-
- Radio buttons only have inButton, so we ignore the inPartCode.
-
- Save the current drawing environment. Iterate through all the devices
- (screens), drawing the control in color or black and white depending
- on the screen depth. Once done, restore the drawing environment and
- return.
- **************************************************************************/
- void
- LGBRadio::Draw(long inPartCode)
- {
- // if we're invisible, don't draw
- if (mControl->contrlVis == false) return;
-
- // save the font
- short font,size,mode,face;
- {
- GrafPtr port;
- ::GetPort(&port);
- font = port->txFont;
- size = port->txSize;
- mode = port->txMode;
- face = port->txFace;
- }
-
- // save the pen colors // will probably crash SEs, so test first
- RGBColor fore,back;
- if (UGBDraw::ColorQDIsPresent()) {
- ::GetForeColor(&fore);
- ::GetBackColor(&back);
- }
-
- // save the clip region
- RgnHandle saveClip = ::NewRgn();
- if (!saveClip) return;
- ::GetClip(saveClip);
-
- // make the pen something sensible
- ::PenNormal();
- ::ForeColor(blackColor);
- ::BackColor(whiteColor);
-
- // loop through all the devices (screens)
- UGBDraw::Offscreen offscreen;
- LGBDeviceIterator device;
- device.Init(mControl->contrlRect);
- short depth = 0;
- do {
- depth = device.Next();
- if (depth == 0) break; // all done with devices
- UGBDraw::OffscreenPre(offscreen);
- if ((depth < 4)
- || (depth == 4 && device.mDeviceIsColor)) {
- DrawBW();
- } else {
- DrawColor();
- }
- UGBDraw::OffscreenPost(offscreen);
- } while(true);
-
- // restore the clip region
- ::SetClip(saveClip);
- ::DisposeRgn(saveClip);
-
- // restore the pen
- if (UGBDraw::ColorQDIsPresent()) {
- ::RGBForeColor(&fore);
- ::RGBBackColor(&back);
- }
-
- // restore the font
- ::TextFont(font);
- ::TextSize(size);
- ::TextMode(mode);
- ::TextFace(face);
- }
-
- /**************************************************************************
- Test()
-
- Return inButton if the point is in our rect
- **************************************************************************/
- Boolean
- LGBRadio::Test(Point inHitPt)
- {
- return ::PtInRect(inHitPt,&(mControl->contrlRect));
- }
-
- /**************************************************************************
- CalcCRgn()
-
- Calculate the control's region in the given region handle. Just
- return our rect as a region
- **************************************************************************/
- void
- LGBRadio::CalcCRgn(RgnHandle ioRgn)
- {
- if (!ioRgn) return; // idiot resistance
- ::RectRgn(ioRgn,&(mControl->contrlRect));
- }
-
- //—————————————————————————————————————————————————————————————————————————
- // Draw
- //—————————————————————————————————————————————————————————————————————————
-
- /**************************************************************************
- DrawBW()
-
- Draw the control in 1-bit. Make no color QD calls here.
- **************************************************************************/
- void
- LGBRadio::DrawBW(void)
- {
- // Set the pen to black, 1x1
- ::PenNormal();
-
- // set up our font
- if (!mUseWFont) LGBControl::SetupFont();
-
- // calculate box locations
- Rect radiobox,titleBox;
- CalcBoxes(radiobox,titleBox);
-
- // draw the parts
- DrawRadio(radiobox);
- DrawTitle(titleBox,mControl->contrlHilite == 255);
- }
-
- /**************************************************************************
- DrawColor()
-
- Draw the control in color, either active or inactive
- **************************************************************************/
- void
- LGBRadio::DrawColor(void)
- {
- UGBDraw::PenNormal();
- ::EraseRect(&(mControl->contrlRect));
-
- if (mControl->contrlHilite == 255) {
- DrawColorInactive();
- } else {
- DrawColorActive();
- }
-
- // restore the pen
- ::PenNormal();
- UGBDraw::PenReallyNormal();
- }
-
- /**************************************************************************
- DrawColorInactive()
-
- Draw the control in color, inactive state.
- **************************************************************************/
- void
- LGBRadio::DrawColorInactive(void)
- {
- // set the pen to inactive grey, background to light grey
- UGBDraw::PenFrameInactive();
- UGBDraw::Background();
-
- // set up our font
- if (!mUseWFont) LGBControl::SetupFont();
-
- // calculate box locations
- Rect radiobox,titleBox;
- CalcBoxes(radiobox,titleBox);
-
- // draw the parts
- DrawRadio(radiobox);
- DrawTitle(titleBox);
- }
-
- /**************************************************************************
- DrawColorActive()
-
- Draw the control in color, inactive state
- **************************************************************************/
- void
- LGBRadio::DrawColorActive(void)
- {
- // set the pen to active black, background to light grey
- UGBDraw::PenFrameActive();
- UGBDraw::Background();
-
- // set up our font
- if (!mUseWFont) LGBControl::SetupFont();
-
- // calculate box locations
- Rect radiobox,titleBox;
- CalcBoxes(radiobox,titleBox);
-
- // draw the title
- DrawTitle(titleBox);
-
- // draw the radio
- DrawRadioColor(radiobox);
- }
-
-
- /**************************************************************************
- DrawRadioColor()
-
- Draw the radio button (just the cirular part, not the title)
- in color. This is fairly icky, so it deserves its own function
- **************************************************************************/
- void
- LGBRadio::DrawRadioColor(const Rect &inRadiobox)
- {
- if (mControl->contrlHilite) { // draw flat, shouldn't occur any more
- UGBDraw::Background();
- UGBDraw::PenFrameActive();
- DrawRadio(inRadiobox);
- } else { // draw 3D
- // draw the frame
- ::FrameOval(&inRadiobox);
-
- // erase the guts if not tristated
- const short value = mControl->contrlValue;
- if (value <= 1) { // erase the innerds
- Rect eraseMe;
- eraseMe.top = inRadiobox.top + 1;
- eraseMe.left = inRadiobox.left + 1;
- eraseMe.right = inRadiobox.right - 1;
- eraseMe.bottom = inRadiobox.bottom - 1;
- UGBDraw::BackGrey(UGBDraw_greyF);
- ::EraseOval(&eraseMe);
- UGBDraw::Background();
- }
-
- if (value == 0) { // empty/convex
- Rect box = inRadiobox;
-
- UGBDraw::ForeGrey(UGBDraw_greyE);
- ::MoveTo(box.left + 6, box.top + 2);
- ::LineTo(box.left + 3, box.top + 5);
- ::MoveTo(box.left + 4, box.top + 5);
- ::LineTo(box.left + 7, box.top + 2);
- ::MoveTo(box.left + 3, box.top + 5);
- ::LineTo(box.left + 3, box.top + 7);
-
- UGBDraw::ForeGrey(UGBDraw_greyD);
- ::MoveTo(box.left + 3, box.top + 8);
- ::LineTo(box.left + 4, box.top + 8);
- ::LineTo(box.left + 4, box.top + 6);
- ::LineTo(box.left + 6, box.top + 6);
- ::LineTo(box.left + 6, box.top + 4);
- ::LineTo(box.left + 7, box.top + 4);
- ::LineTo(box.left + 7, box.top + 3);
- ::LineTo(box.left + 8, box.top + 3);
- ::LineTo(box.left + 8, box.top + 2);
- ::MoveTo(box.left + 5, box.top + 5);
- ::Line(0,0);
- ::MoveTo(box.left + 7, box.top + 5);
- ::Line(0,0);
- ::MoveTo(box.left + 5, box.top + 7);
- ::Line(0,0);
-
- UGBDraw::ForeGrey(UGBDraw_greyB);
- ::MoveTo(box.left + 3, box.top + 9);
- ::LineTo(box.left + 5, box.top + 9);
- ::LineTo(box.left + 5, box.top + 8);
- ::LineTo(box.left + 6, box.top + 8);
- ::LineTo(box.left + 6, box.top + 7);
- ::LineTo(box.left + 7, box.top + 7);
- ::LineTo(box.left + 7, box.top + 6);
- ::LineTo(box.left + 8, box.top + 6);
- ::LineTo(box.left + 8, box.top + 4);
-
- UGBDraw::ForeGrey(UGBDraw_greyA);
- ::MoveTo(box.left + 6, box.top + 9);
- ::LineTo(box.left + 7, box.top + 9);
- ::LineTo(box.left + 7, box.top + 8);
- ::LineTo(box.left + 8, box.top + 8);
- ::LineTo(box.left + 8, box.top + 7);
- ::LineTo(box.left + 9, box.top + 7);
- ::LineTo(box.left + 9, box.top + 2);
-
- UGBDraw::ForeGrey(UGBDraw_grey8);
- ::MoveTo(box.left + 4, box.top + 10);
- ::LineTo(box.left + 7, box.top + 10);
- ::MoveTo(box.left + 8, box.top + 9);
- ::LineTo(box.left + 9, box.top + 9);
- ::LineTo(box.left + 9, box.top + 8);
- ::MoveTo(box.left + 10, box.top + 7);
- ::LineTo(box.left + 10, box.top + 4);
-
- } else if (value == 1) { // draw with a dot/concave
- Rect box = inRadiobox;
-
- UGBDraw::ForeGrey(UGBDraw_greyE);
- ::MoveTo(box.left + 9, box.top + 5);
- ::LineTo(box.left + 9, box.top + 7);
- ::MoveTo(box.left + 5, box.top + 9);
- ::LineTo(box.left + 7, box.top + 9);
-
- UGBDraw::ForeGrey(UGBDraw_greyD);
- ::MoveTo(box.left + 3, box.top + 9);
- ::LineTo(box.left + 4, box.top + 9);
- ::MoveTo(box.left + 9, box.top + 3);
- ::LineTo(box.left + 9, box.top + 4);
-
- UGBDraw::ForeGrey(UGBDraw_greyB);
- ::MoveTo(box.left + 2, box.top + 9);
- ::LineTo(box.left + 2, box.top + 8);
- ::LineTo(box.left + 3, box.top + 8);
- ::MoveTo(box.left + 8, box.top + 3);
- ::LineTo(box.left + 8, box.top + 2);
- ::LineTo(box.left + 9, box.top + 2);
-
- UGBDraw::ForeGrey(UGBDraw_greyA);
- ::MoveTo(box.left + 2, box.top + 7);
- ::LineTo(box.left + 2, box.top + 4);
- ::LineTo(box.left + 4, box.top + 2);
- ::LineTo(box.left + 7, box.top + 2);
-
- UGBDraw::ForeGrey(UGBDraw_grey8);
- ::MoveTo(box.left + 1, box.top + 7);
- ::LineTo(box.left + 1, box.top + 4);
- ::LineTo(box.left + 4, box.top + 1);
- ::LineTo(box.left + 7, box.top + 1);
- ::MoveTo(box.left + 2, box.top + 2);
- ::Line(0,0);
-
- // draw •
- UGBDraw::PenFrameActive();
- Rect x = inRadiobox;
- ::InsetRect(&x,3,3);
- ::PaintOval(&x);
- } else if (value == 2) { // tristate
- // fabricate a ltGray pattern on the fly. We don't
- // have quickdraw globals and I'm not going to set
- // up A4 to get them.
- unsigned char ltGrey[8];
- ltGrey[0] = ltGrey[2] = ltGrey[4] = ltGrey[6] = 0x88;
- ltGrey[1] = ltGrey[3] = ltGrey[5] = ltGrey[7] = 0x22;
-
- UGBDraw::ForeGrey(UGBDraw_grey7);
- UGBDraw::BackGrey(UGBDraw_greyD);
-
- Rect grayRect = inRadiobox;
- ::InsetRect(&grayRect,1,1);
- ::FillOval(&grayRect,(PatPtr) <Grey);
- }
- }
- }
-
- /**************************************************************************
- CalcBoxes()
-
- Figure out where to draw the checkbox and the title
- **************************************************************************/
- void
- LGBRadio::CalcBoxes(Rect &outRadiobox, Rect &outTitleBox)
- {
- const Rect contrlRect = mControl->contrlRect;
- const StringPtr title = mControl->contrlTitle;
- LGBControl::CalcBoxes(contrlRect,title,
- outRadiobox,outTitleBox);
- }
-
- /**************************************************************************
- DrawRadio()
-
- Draw the radio. Draw the "•", everything
- but the title and the background.
- **************************************************************************/
- void
- LGBRadio::DrawRadio(const Rect &inRadiobox)
- {
- // draw the frame
- ::FrameOval(&inRadiobox);
-
- // draw the • or erase the guts, if empty or •. No erase if tristated
- const short value = mControl->contrlValue;
- if (value <= 1) { // erase the innerds
- Rect eraseMe;
- eraseMe.top = inRadiobox.top + 1;
- eraseMe.left = inRadiobox.left + 1;
- eraseMe.right = inRadiobox.right - 1;
- eraseMe.bottom = inRadiobox.bottom - 1;
- ::EraseOval(&eraseMe);
- }
-
- if (value == 0) { // empty. Do nothing (already erased above)
- } else if (value == 1) { // •
- Rect x = inRadiobox;
- ::InsetRect(&x,3,3);
- ::PaintOval(&x);
- } else if (value == 2) { // tristate
- // fabricate a ltGray pattern on the fly. We don't
- // have quickdraw globals and I'm not going to set
- // up A4 to get them.
- unsigned char ltGrey[8];
- ltGrey[0] = ltGrey[2] = ltGrey[4] = ltGrey[6] = 0x88;
- ltGrey[1] = ltGrey[3] = ltGrey[5] = ltGrey[7] = 0x22;
-
- Rect grayRect = inRadiobox;
- ::InsetRect(&grayRect,1,1);
- ::FillOval(&grayRect,(PatPtr) <Grey);
- }
-
- // draw highlight
- if ((mControl->contrlHilite)
- && (mControl->contrlHilite != 255)) {
- ::PenNormal();
- Rect hilite = inRadiobox;
- ::InsetRect(&hilite,1,1);
- ::FrameOval(&hilite);
- }
- }
-
- /**************************************************************************
- DrawTitle()
-
- Draw the title.
- **************************************************************************/
- void
- LGBRadio::DrawTitle(const Rect &inTitleBox, Boolean inDim1Bit)
- {
- const StringPtr title = mControl->contrlTitle;
- ::TextBox(title + 1,*title,&inTitleBox,teFlushDefault);
-
- // grey out the name if inactive and B&W
- if (inDim1Bit) {
- unsigned char grey[8];
- grey[0] = grey[2] = grey[4] = grey[6] = 0xAA;
- grey[1] = grey[3] = grey[5] = grey[7] = 0x55;
- ::PenPat((PatPtr) grey);
- ::PenMode(patBic);
- ::PaintRect(&inTitleBox);
- ::PenNormal();
- }
- }
-
-